package cn.iocoder.yudao.module.trade.order.service.calculator;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.api.infrastructure.config.dto.MemberConfigRespDTO;
import cn.iocoder.yudao.module.api.promotion.activity.enums.PromotionTypeEnum;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeOrderTypeEnum;
import cn.iocoder.yudao.module.trade.order.bo.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.order.bo.TradePriceCalculateRespBO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
import static cn.iocoder.yudao.module.api.trade.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL;

/**
 * 使用积分的 {@link TradePriceCalculator} 实现类
 *
 * @author owen
 */
@Component
@Order(TradePriceCalculator.ORDER_POINT_DEDUCT)
@Slf4j
public class TradePointDeductPriceCalculator implements TradePriceCalculator {

    @Override
    public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
        // 0.1 判断订单类型是否不为积分兑换活动，积分兑换订单不再享受积分抵扣
        if (ObjectUtil.equal(result.getType(), TradeOrderTypeEnum.POINT.getType())) {
            log.debug("[calculate][是积分兑换活动，积分抵扣不生效]");
            return;
        }
        if (ObjectUtil.equal(result.getType(), TradeOrderTypeEnum.GROUPON.getType())) {
            log.debug("[calculate][是团购套餐订单，不支持积分抵扣]");
            return;
        }
        // 0.2 校验是否使用积分抵扣
        if (!param.isUsePointDeduction()) {
            log.debug("[calculate][订单未明确使用积分抵扣，积分抵扣不生效]");
            return;
        }
        // 1.1 校验用户积分余额
        if (result.getTotalPoint() == null || result.getTotalPoint() <= 0) {
            log.debug("[calculate][用户积分余额为空，积分抵扣不生效]");
            return;
        }
        // 1.2 校验积分抵扣是否开启
        MemberConfigRespDTO config = result.getMemberConfig();
        if (config == null) {
            log.debug("[calculate][未获取到用户中心配置，积分抵扣不生效]");
            return;
        }
        if (config.isPointDeductDisable()) {
            log.debug("[calculate][积分抵扣功能未开启，积分抵扣不生效]");
            return;
        }
        List<TradePriceCalculateRespBO.OrderItem> orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected);
        // 2.1 计算积分优惠金额
        int sumDeductCount = 0;
        for (TradePriceCalculateRespBO.OrderItem item : orderItems) {
            sumDeductCount += item.getSkuPointDeductCount() * item.getCount();
        }
        log.debug("[calculate][计算积分优惠金额，需要 {} 个积分抵扣", sumDeductCount);
        int diffPoint = result.getTotalPoint() - sumDeductCount;
        if (diffPoint < 0) {
            log.warn("[calculate][积分抵扣失败，积分不足，还差 {} 个积分]", Math.abs(diffPoint));
            return;
        }
        int sumPointPrice = calculatePointPrice(config, sumDeductCount, result);
        // 2.2 计算分摊的积分、抵扣金额
        List<Integer> dividePrices = TradePriceCalculatorHelper.dividePrice(orderItems, sumPointPrice);
        // 3.1 记录优惠明细
        TradePriceCalculatorHelper.addPromotion(result, orderItems,
                param.getUserId(), "积分抵扣", PromotionTypeEnum.POINT.getValue(),
                StrUtil.format("积分抵扣：省 {} 元", TradePriceCalculatorHelper.formatPrice(sumPointPrice)),
                dividePrices);
        // 3.2 更新 SKU 优惠金额
        for (int i = 0, n = orderItems.size(); i < n; i++) {
            TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i);
            orderItem.setPointPrice(dividePrices.get(i));
            TradePriceCalculatorHelper.recountPayPrice(orderItem);
        }
        TradePriceCalculatorHelper.recountAllPrice(result);
        log.debug("[calculate][积分抵扣价格计算完成] {}", result.getPrice());
    }

    private Integer calculatePointPrice(MemberConfigRespDTO config, Integer deductPoint, TradePriceCalculateRespBO result) {
        if (deductPoint == null) {
            deductPoint = 0;
        }
        if (config.getPointTradeDeductMaxPoint() > 0) {
            deductPoint = Math.min(deductPoint, config.getPointTradeDeductMaxPoint());
        }
        log.debug("[calculatePointPrice][每个订单最多可以使用的积分数量为 {}，实际使用积分为 {}，1 个积分抵扣 {} 分]",
                config.getPointTradeDeductMaxPoint(), deductPoint, config.getPointTradeDeductUnitPrice());
        // 积分优惠金额（分）
        int pointPrice = deductPoint * config.getPointTradeDeductUnitPrice(); // 确保整数抵扣
        log.debug("[calculatePointPrice][积分 {} 抵扣金额 {}, 原本需支付金额 {}]", deductPoint, pointPrice, result.getPrice().getPayPrice());
        if (result.getPrice().getPayPrice() <= pointPrice) {
            // 禁止 0 元购，即不允许积分全额抵扣
            throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL);
        }
        // 记录使用的积分
        result.setDeductPoint(deductPoint);
        return pointPrice;
    }

}
